// package com.jourwon.spring.boot.config;
//
// import com.alibaba.fastjson.JSON;
// import lombok.extern.slf4j.Slf4j;
// import org.apache.http.Header;
// import org.apache.http.HeaderElement;
// import org.apache.http.HeaderElementIterator;
// import org.apache.http.HttpHost;
// import org.apache.http.client.HttpClient;
// import org.apache.http.client.protocol.HttpClientContext;
// import org.apache.http.config.Registry;
// import org.apache.http.config.RegistryBuilder;
// import org.apache.http.conn.ConnectionKeepAliveStrategy;
// import org.apache.http.conn.socket.ConnectionSocketFactory;
// import org.apache.http.conn.socket.PlainConnectionSocketFactory;
// import org.apache.http.conn.ssl.NoopHostnameVerifier;
// import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
// import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
// import org.apache.http.impl.client.HttpClientBuilder;
// import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
// import org.apache.http.message.BasicHeader;
// import org.apache.http.message.BasicHeaderElementIterator;
// import org.apache.http.protocol.HTTP;
// import org.apache.http.ssl.SSLContextBuilder;
// import org.springframework.boot.context.properties.EnableConfigurationProperties;
// import org.springframework.context.annotation.Bean;
// import org.springframework.context.annotation.Configuration;
// import org.springframework.http.client.ClientHttpRequestFactory;
// import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
// import org.springframework.http.converter.StringHttpMessageConverter;
// import org.springframework.web.client.DefaultResponseErrorHandler;
// import org.springframework.web.client.RestTemplate;
//
// import javax.annotation.Resource;
// import javax.net.ssl.HostnameVerifier;
// import javax.net.ssl.SSLContext;
// import java.nio.charset.StandardCharsets;
// import java.security.KeyManagementException;
// import java.security.KeyStoreException;
// import java.security.NoSuchAlgorithmException;
// import java.util.*;
// import java.util.concurrent.TimeUnit;
//
// /**
//  * RestTemplate 客户端配置 Httpclient 的线程池
//  *
//  * @author JourWon
//  * @date 2022/6/19
//  */
// @Slf4j
// @Configuration
// @EnableConfigurationProperties(HttpClientPoolProperties.class)
// public class RestTemplateHttpClientConfig {
//
//     @Resource
//     private HttpClientPoolProperties httpClientPoolProperties;
//
//     @Bean
//     public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
//         // 1.实例化使用httpclient的RestTemplate
//         RestTemplate restTemplate = new RestTemplate(factory);
//         // 2.采用RestTemplate内部的MessageConverter
//         // 重新设置StringHttpMessageConverter字符集，解决中文乱码问题
//         // modifyDefaultCharset(restTemplate);
//         restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
//         // 3.设置错误处理器
//         restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
//         return restTemplate;
//     }
//
//     /**
//      * 创建HTTP客户端工厂
//      *
//      * @return ClientHttpRequestFactory
//      */
//     @Bean
//     public ClientHttpRequestFactory clientHttpRequestFactory() {
//         // 1.检查配置maxTotalConnection 和 maxConnectionPerRoute
//         if (httpClientPoolProperties.getMaxTotal() <= 0) {
//             throw new IllegalArgumentException("invalid maxTotalConnection: " +
//                     httpClientPoolProperties.getMaxTotal());
//         }
//         if (httpClientPoolProperties.getMaxPerRoute() <= 0) {
//             throw new IllegalArgumentException("invalid maxConnectionPerRoute: " +
//                     httpClientPoolProperties.getMaxPerRoute());
//         }
//         // 2.创建clientHttpRequestFactory
//         HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
//         // 连接超时
//         clientHttpRequestFactory.setConnectTimeout(httpClientPoolProperties.getConnectTimeout());
//         // 数据读取超时时间，即SocketTimeout
//         clientHttpRequestFactory.setReadTimeout(httpClientPoolProperties.getReadTimeout());
//         // 从连接池获取请求连接的超时时间，不宜过长，必须设置，比如连接不够用时，时间过长将是灾难性的
//         clientHttpRequestFactory.setConnectionRequestTimeout(httpClientPoolProperties.getConnectionRequestTimout());
//         return clientHttpRequestFactory;
//     }
//
//     /**
//      * 创建httpClient
//      *
//      * @return HttpClient
//      */
//     @Bean
//     public HttpClient httpClient() {
//         HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
//         try {
//             // 设置信任ssl访问
//             SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
//             httpClientBuilder.setSSLContext(sslContext);
//             HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
//             SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
//             Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
//                     // 注册http和https请求
//                     .register("http", PlainConnectionSocketFactory.getSocketFactory())
//                     .register("https", sslConnectionSocketFactory).build();
//             // 使用Httpclient连接池的方式配置(推荐)，同时支持netty，okHttp以及其他http框架
//             PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
//             // 最大连接数
//             poolingHttpClientConnectionManager.setMaxTotal(httpClientPoolProperties.getMaxTotal());
//             // 同路由并发数
//             poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientPoolProperties.getMaxPerRoute());
//             // 配置连接池
//             httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
//             // 重试次数，调用接口响应状态码非200应该重试，但是这里测试没有重试，需要研究一些什么问题
//             httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientPoolProperties.getRetryCount(), true));
//
//             // 设置默认请求头
//             httpClientBuilder.setDefaultHeaders(getDefaultHeaders());
//             // 设置长连接保持策略
//             httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy());
//
//             // 启动清理线程，也可以启用用CloseableHttpClient的清理线程
//             // Thread t = new IdleConnectionMonitorThread(connectionManager);
//             // t.setName("httpconnections-pool-evict-thread");
//             // t.start();
//
//             // 设置后台线程剔除失效连接
//             httpClientBuilder.evictExpiredConnections();
//             httpClientBuilder.evictIdleConnections(httpClientPoolProperties.getMaxIdleTime(), TimeUnit.MILLISECONDS);
//             return httpClientBuilder.build();
//         } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
//             log.error("初始化HTTP连接池出错", e);
//         }
//         return null;
//     }
//
//     /**
//      * 配置长连接保持策略
//      *
//      * @return ConnectionKeepAliveStrategy 长连接保持策略
//      */
//     public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
//         return (response, context) -> {
//             // Honor 'keep-alive' header
//             HeaderElementIterator it = new BasicHeaderElementIterator(
//                     response.headerIterator(HTTP.CONN_KEEP_ALIVE));
//             while (it.hasNext()) {
//                 HeaderElement he = it.nextElement();
//                 log.info("HeaderElement:{}", JSON.toJSONString(he));
//                 String param = he.getName();
//                 String value = he.getValue();
//                 if (value != null && "timeout".equalsIgnoreCase(param)) {
//                     try {
//                         return Long.parseLong(value) * 1000;
//                     } catch (NumberFormatException ignore) {
//                         log.error("解析长连接过期时间异常", ignore);
//                     }
//                 }
//             }
//             HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST);
//             // 如果请求目标地址,单独配置了长连接保持时间,使用该配置
//             Optional<Map.Entry<String, Integer>> any = Optional.ofNullable(httpClientPoolProperties.getKeepAliveTargetHost()).orElseGet(HashMap::new)
//                     .entrySet().stream().filter(e -> e.getKey().equalsIgnoreCase(target.getHostName())).findAny();
//             // 否则使用默认长连接保持时间
//             return any.map(en -> en.getValue()).orElse(httpClientPoolProperties.getKeepAliveTime());
//         };
//     }
//
//     /**
//      * 设置默认请求头
//      *
//      * @return List<Header> 请求头列表
//      */
//     private List<Header> getDefaultHeaders() {
//         List<Header> headers = new ArrayList<>();
//         headers.add(new BasicHeader("Accept", "*/*"));
//         headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate, br"));
//         headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.9"));
//         headers.add(new BasicHeader("Connection", "keep-alive"));
//         headers.add(new BasicHeader("User-Agent",
//                 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"));
//         return headers;
//     }
//
//     // /**
//     //  * 修改默认的字符集类型为utf-8
//     //  *
//     //  * @param restTemplate
//     //  */
//     // private void modifyDefaultCharset(RestTemplate restTemplate) {
//     //     List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
//     //     HttpMessageConverter<?> converterTarget = null;
//     //     for (HttpMessageConverter<?> item : converterList) {
//     //         if (StringHttpMessageConverter.class == item.getClass()) {
//     //             converterTarget = item;
//     //             break;
//     //         }
//     //     }
//     //     if (null != converterTarget) {
//     //         converterList.remove(converterTarget);
//     //     }
//     //     converterList.add(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
//     // }
//
//     // pool监测线程，定期移除过期连接、空闲连接
//     // public static class IdleConnectionMonitorThread extends Thread {
//     //
//     //     private final HttpClientConnectionManager connMgr;
//     //     public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
//     //         super();
//     //         this.connMgr = connMgr;
//     //     }
//     //
//     //     @Override
//     //     public void run() {
//     //         try {
//     //             while (true) {
//     //                 synchronized (this) {
//     //                     Thread.sleep(5000);
//     //                     connMgr.closeExpiredConnections();
//     //                     connMgr.closeIdleConnections(5, TimeUnit.SECONDS);
//     //                 }
//     //             }
//     //         } catch (InterruptedException e) {
//     //             e.printStackTrace();
//     //         }
//     //     }
//     // }
//
// }
